// gameswf_sound_hander_bass.cpp
//		hacked from gameswf_sound_handler_sdl.cpp

// This source code has been donated to the Public Domain.  Do
// whatever you want with it.
//		A gameswf::sound_handler that uses BASS for output
//		BASS can be downloaded from http://www.un4seen.com/


#include "gameswf/gameswf.h"
#include "gameswf/base/container.h"
#include "gameswf/gameswf_log.h"
#include "gameswf/gameswf_types.h"	// for IF_VERBOSE_* macros

#define GAMESWF_BASS_SUPPORT
#ifdef	GAMESWF_BASS_SUPPORT

// options
//#define		HANDLER_OWNS_BASS		// some applications may initialize/deinit in the central sound-engine
//#define		HANDLER_SETS_VOLUME		// volume may be controlled downstream


// audio library
#include "bass/bass.h"


// Use SDL_mixer to handle gameswf sounds.
struct BASS_sound_handler : gameswf::sound_handler
{
	bool	m_opened;
	bool	m_stereo;
	array<HSAMPLE>	m_samples;		// BASS samples as DWORDS; they get mangled somewhere by GameSWF

	#define	SAMPLE_RATE 44100
	#define MIX_CHANNELS 8
	#define CHANNELS 2			// stereo - 2, mono - 1
	#define BUFSIZE 4096		// for 44100 bufsize 1024 is small
	#define	VOLUME 70

	BASS_sound_handler()	:
		m_opened(false)
	{
#ifdef	HANDLER_OWNS_BASS
		unsigned long	Flags = 0;
		if (CHANNELS != 2) Flags|=BASS_DEVICE_MONO;


		if (!BASS_Init(	1,				// first valid sound-driver
						SAMPLE_RATE,	// sound-driver
						Flags,			// default to 16bit stereo
						0,				// window ID. 0 is current
						NULL))			// ClassID. 0 is current
		{
			gameswf::log_error("can't open BASS sound system");
			return;
		}	
#endif // HANDLER_OWNS_BASS
		m_opened = true;		// sound system is up
	}

	~BASS_sound_handler()
	{
		if (m_opened)
		{
			// BASS and FMOD manages the creation/destruction of their sounds on their own
#ifdef	HANDLER_OWNS_BASS
			BASS_Free();
#endif	//HANDLER_OWNS_BASS
		}
	}


	virtual int	create_sound(
		void* data,
		int data_bytes,
		int sample_count,
		format_type format,
		int sample_rate,
		bool stereo)
	// Called by gameswf to create a sample.  We'll return a sample ID that gameswf
	// can use for playing it.
	{
		if (m_opened == false)
		{
			return 0;
		}
		HSAMPLE SampleID  = 0;

		if (format == sound_handler::FORMAT_NATIVE16)
		{
			// raw data; create a sample and copy it over
			void* pSoundBuffer= (void*)BASS_SampleCreate(
				data_bytes,			// length in bytes
				SAMPLE_RATE,		// sample rate
				(stereo) ? 2 : 1,	// channels
				MIX_CHANNELS,		// max channels simultaneous
				0					// no flags
			);

			if (data)
			{
				memcpy(pSoundBuffer, data, data_bytes);
				// TODO:
				// deprecated? 
				//SampleID= BASS_SampleCreateDone(); // get the new sample's handle 
			}

		} else
		if (format == sound_handler::FORMAT_MP3)
		{

			unsigned long		Flags = 0;
			if (!stereo)		Flags|=BASS_SAMPLE_MONO;

			// BASS will take a good stab of working out the File Format from the ID
			SampleID = BASS_SampleLoad(
				true,		// loaded from memory
				data,		// data-chunk to load from
				0,			// file offset (invalid for load from memory)
				data_bytes,	// size of data
				MIX_CHANNELS,// max simultaneous playbacks
				Flags			// flags
			);
		}

		if (!SampleID)
		{
			// Unhandled format.
			gameswf::log_error("Unable to load sound\n");
			int	Error = BASS_ErrorGetCode();
			gameswf::log_error("BASS Error Code %i\n", Error);
		}
		m_samples.push_back(SampleID);

		return m_samples.size()-1;
	}


	virtual void	play_sound(int sound_handle, int loop_count )	
	// Play the index'd sample.
	{
		HSAMPLE	SoundID = get_sound(sound_handle);
		if (SoundID >  0 )
		{
			HCHANNEL Channel = BASS_SampleGetChannel(SoundID, false);
			if (Channel)
			{
				if (BASS_ChannelPlay(Channel, true))
				{
#ifdef HANDLER_SETS_VOLUME
					BASS_ChannelSetAttributes(
						Channel,	// Channel ID
						-1,			// keep current frequency
						VOLUME,		// volume 0..100
						-101);		// panning. Leave current
#endif // HANDLER_SETS_VOLUME					
					// Bass doesn't support a loop-n-times
					// functionality. We might be able to hack it using the event callbacks.
					//
					//		unsigned long		ChannelFlags = 0;
					//		if (loop_count > 0) ChannelFlags |= BASS_SAMPLE_LOOP;
					//		BASS_ChannelSetFlags(
					//			Channel,
					//			ChannelFlags);
						
				}
			}
		}
	}

	
	virtual void	stop_sound(int sound_handle)
	{
		HSAMPLE	SoundID = get_sound(sound_handle);
		if (SoundID >  0 )
		{
			BASS_SampleStop(SoundID);
			m_samples[sound_handle] = 0;
			return;
		}
	}


	virtual void	delete_sound(int sound_handle)
	// gameswf calls this when it's done with a sample.
	{
		HSAMPLE	SoundID = get_sound(sound_handle);
		if (SoundID >  0 )
		{
			BASS_SampleFree(SoundID);
		}
	}

	HSAMPLE			get_sound(int	sound_handle)
	{
		if (sound_handle < 0 || sound_handle >=m_samples.size()) return 0;
		return m_samples[sound_handle];
	}


//	TODO: as yet unimplemented
	virtual int	load_sound(const char* url) { return 0; };
	virtual void append_sound(int sound_handle, void* data, int data_bytes) { return ; };
	virtual void	play_sound(gameswf::as_object* listener_obj, int sound_handle, int loop_count /* , volume, pan, etc? */) {};
	virtual void	set_volume(int sound_handle, int volume) {};
	virtual void	set_max_volume(int vol) {};
	virtual void	stop_all_sounds() {};
};


gameswf::sound_handler*	gameswf::create_sound_handler_bass()
// Factory.
{
	return new BASS_sound_handler;
}

#endif //	GAMESWF_BASS_SUPPORT